Skip to content

Add onnxsim as an alternative ONNX simplification backend - #2018

Open
take-cheeze wants to merge 1 commit into
NVIDIA:mainfrom
take-cheeze:claude/re-enable-onnxsim-c1wpem
Open

Add onnxsim as an alternative ONNX simplification backend#2018
take-cheeze wants to merge 1 commit into
NVIDIA:mainfrom
take-cheeze:claude/re-enable-onnxsim-c1wpem

Conversation

@take-cheeze

@take-cheeze take-cheeze commented Jul 26, 2026

Copy link
Copy Markdown

What does this PR do?

Type of change: New feature

Adds onnxsim as an alternative ONNX simplification backend for
modelopt.onnx.quantization.quantize(..., simplify=True) and the --simplify
CLI flag, while keeping onnxslim as the default. Previously the simplifier
was hard-wired to onnxslim; this makes the two interchangeable via a new
simplify_backend argument (--simplify_backend on the CLI) that accepts
"onnxslim" (default) or "onnxsim".

Details:

  • quantize.py: quantize() and _preprocess_onnx() gain a
    simplify_backend: str = "onnxslim" argument. The simplify block dispatches
    on it — onnxslim.slim(..., skip_fusion_patterns=["FusionGemm"]) for
    onnxslim, onnxsim.simplify(...) for onnxsim. An unknown backend name or
    a missing onnxsim install fails loudly (raised before the guarded block),
    whereas genuine simplification failures still fall back gracefully to the
    original model, exactly as before. onnxsim is imported lazily so it is only
    required when actually selected.
  • __main__.py: adds --simplify_backend with choices=["onnxslim", "onnxsim"],
    default onnxslim, wired into the quantize(...) call.
  • pyproject.toml / uv.lock: adds onnxsim>=0.7.0 to the onnx extra
    alongside the existing onnxslim>=0.1.76. onnxsim 0.7.0 ships wheels for
    Python 3.12+ and aarch64, so no platform markers are needed.

Usage

from modelopt.onnx.quantization.quantize import quantize

# Default behavior is unchanged (uses onnxslim):
quantize("model.onnx", simplify=True)

# Opt into onnxsim instead:
quantize("model.onnx", simplify=True, simplify_backend="onnxsim")
# CLI — default (onnxslim):
python -m modelopt.onnx.quantization --onnx_path model.onnx --simplify

# CLI — onnxsim backend:
python -m modelopt.onnx.quantization --onnx_path model.onnx --simplify --simplify_backend onnxsim

Testing

  • Updated the _preprocess_onnx mock in
    tests/unit/onnx/quantization/test_quantize_api.py for the new argument;
    the existing unit suite for the quantize API continues to pass.
  • The existing GPU test tests/gpu/onnx/test_simplify.py exercises the
    default (onnxslim) simplify path end-to-end.
  • Locally verified pyproject.toml and uv.lock parse, the lock resolves
    onnxsim 0.7.0 (deps onnx, rich) with onnxslim untouched, and the
    changed Python files pass ruff format --check.
  • Not run in this environment: the GPU simplify test on the onnxsim path
    (needs a GPU and onnxsim installed).

Before your PR is "Ready for review"

  • Is this change backward compatible?: ✅ — simplify defaults to the existing
    onnxslim backend; no existing call site or CLI invocation changes behavior.
  • If you copied code from any other sources or added a new PIP dependency, did
    you follow guidance in CONTRIBUTING.md: ✅ — added onnxsim to the optional
    onnx extra and relocked uv.lock; no code copied.
  • Did you write any new necessary tests?: ❌ — updated the existing
    _preprocess_onnx mock only; a dedicated simplify_backend-selection unit
    test is not yet added (happy to add one covering the dispatch and the
    invalid-backend ValueError if reviewers want it).
  • Did you update Changelog?: ✅ — added an entry under the 0.46 New Features
    section.
  • Did you get Claude approval on this PR?: N/A — will run /claude review once
    opened.

Additional Information

No related issue. Default simplification remains onnxslim; onnxsim is purely
additive and opt-in.

Summary by CodeRabbit

  • New Features
    • Added a --simplify_backend CLI option and corresponding parameter to choose between onnxslim (default) and onnxsim when simplification is enabled.
    • Added support for onnxsim>=0.7.0, including compatible Python and aarch64 environments.
  • Bug Fixes
    • Improved validation and error handling for unsupported or unavailable simplification backends.
    • Simplified models are now saved only after successful validation.

@take-cheeze
take-cheeze requested review from a team as code owners July 26, 2026 09:34
@copy-pr-bot

copy-pr-bot Bot commented Jul 26, 2026

Copy link
Copy Markdown

This pull request requires additional validation before any workflows can run on NVIDIA's runners.

Pull request vetters can view their responsibilities here.

Contributors can view more details about this message here.

@coderabbitai

coderabbitai Bot commented Jul 26, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

The quantization workflow adds selectable ONNX simplification backends. The API and CLI support onnxslim and onnxsim. Backend validation, optional dependency packaging, tests, and changelog documentation are updated.

Changes

ONNX simplification backend selection

Layer / File(s) Summary
Backend API and simplification execution
modelopt/onnx/quantization/quantize.py, tests/unit/onnx/quantization/test_quantize_api.py
quantize accepts and forwards simplify_backend. Preprocessing validates and invokes onnxslim or onnxsim. The test mock matches the updated call signature.
CLI backend selection
modelopt/onnx/quantization/__main__.py
Adds --simplify_backend with onnxslim as the default and forwards the selected value to quantize.
onnxsim packaging and changelog
pyproject.toml, CHANGELOG.rst
Adds onnxsim>=0.7.0 to the ONNX optional dependencies and documents the backend selector and wheel support.

Estimated code review effort: 2 (Simple) | ~10 minutes

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant CLI
  participant quantize
  participant _preprocess_onnx
  participant onnxslim_or_onnxsim
  User->>CLI: select --simplify_backend
  CLI->>quantize: pass simplify_backend
  quantize->>_preprocess_onnx: request simplification
  _preprocess_onnx->>onnxslim_or_onnxsim: invoke selected backend
  onnxslim_or_onnxsim-->>_preprocess_onnx: return simplified model
Loading

Suggested reviewers: kevalmorabia97, gcunhase

🚥 Pre-merge checks | ✅ 6
✅ Passed checks (6 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main change: adding onnxsim as an alternative ONNX simplification backend.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Security Anti-Patterns ✅ Passed The PR adds no prohibited security patterns. The only new dependency, onnxsim 0.7.0, uses permissive MIT/Apache-2.0/BSD-2-Clause licensing.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Warning

CodeRabbit couldn't request changes on this pull request because it doesn't have sufficient GitHub permissions.

Please grant CodeRabbit Pull requests: Read and write permission and re-run the review.

👉 Steps to fix this

Actionable comments posted: 1

🧹 Nitpick comments (1)
tests/unit/onnx/quantization/test_quantize_api.py (1)

92-95: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Exercise backend selection rather than only updating mock arity.

Capture and assert the forwarded default, then add focused tests for onnxsim, unsupported backends, and missing optional dependencies.

Minimal assertion
         simplify_backend,
         quantize_mode,
         opset,
     ):
+        captured["simplify_backend"] = simplify_backend
         return onnx_path, object(), [], True, False, False, {}, {}
...
+    assert captured["simplify_backend"] == "onnxslim"

As per path instructions, tests must add coverage for new features and exercise the behavior they validate.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/unit/onnx/quantization/test_quantize_api.py` around lines 92 - 95,
Expand the quantization API tests around the backend-selection parameter in the
test function receiving simplify_backend, quantize_mode, and opset: capture and
assert its forwarded default, then add focused coverage for the onnxsim backend,
unsupported backend handling, and missing optional dependencies. Ensure the
tests exercise the actual selection behavior rather than only adjusting mock
argument arity.

Source: Path instructions

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@modelopt/onnx/quantization/quantize.py`:
- Line 401: Reorder the new simplify_backend parameter in the quantization
function signature so it appears after autotune_trtexec_args, preserving the
existing positional binding of later parameters such as calibrate_per_node. Keep
its default value unchanged and update any related signature handling
accordingly.

---

Nitpick comments:
In `@tests/unit/onnx/quantization/test_quantize_api.py`:
- Around line 92-95: Expand the quantization API tests around the
backend-selection parameter in the test function receiving simplify_backend,
quantize_mode, and opset: capture and assert its forwarded default, then add
focused coverage for the onnxsim backend, unsupported backend handling, and
missing optional dependencies. Ensure the tests exercise the actual selection
behavior rather than only adjusting mock argument arity.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 22ab02b7-001d-4812-ae75-19e815c5d0fc

📥 Commits

Reviewing files that changed from the base of the PR and between 33d05b0 and d98e6c9.

⛔ Files ignored due to path filters (1)
  • uv.lock is excluded by !**/*.lock
📒 Files selected for processing (5)
  • CHANGELOG.rst
  • modelopt/onnx/quantization/__main__.py
  • modelopt/onnx/quantization/quantize.py
  • pyproject.toml
  • tests/unit/onnx/quantization/test_quantize_api.py

Comment thread modelopt/onnx/quantization/quantize.py Outdated
@gcunhase

Copy link
Copy Markdown
Contributor

Hi @take-cheeze, can you please elaborate on the motivation for this? Are you observing issues with onnxslim? Thanks.

@take-cheeze

Copy link
Copy Markdown
Author

I know the situation in #478 , though onnx-simplifier is now maintained.
I'm currently working on creating regression test suite like: https://github.com/onnxsim/onnxsim/actions/runs/30331687815 (Recent runs could be referrred from https://github.com/onnxsim/onnxsim/actions/workflows/model-regression.yml )
As far as I could say is that sometime onnxslim or onnxsim is better.
The way onnxslim and onnxsim implement is different and now both is reliable so it seems reasonable to be selectable.
How do you think? @inisis

@inisis

inisis commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

I know the situation in #478 , though onnx-simplifier is now maintained. I'm currently working on creating regression test suite like: https://github.com/onnxsim/onnxsim/actions/runs/30331687815 (Recent runs could be referrred from https://github.com/onnxsim/onnxsim/actions/workflows/model-regression.yml ) As far as I could say is that sometime onnxslim or onnxsim is better. The way onnxslim and onnxsim implement is different and now both is reliable so it seems reasonable to be selectable. How do you think? @inisis

@take-cheeze If onnxsim is now well-maintained, I would certainly pick onnxsim up, it's the only one.

@gcunhase

Copy link
Copy Markdown
Contributor

I know the situation in #478 , though onnx-simplifier is now maintained. I'm currently working on creating regression test suite like: https://github.com/onnxsim/onnxsim/actions/runs/30331687815 (Recent runs could be referrred from https://github.com/onnxsim/onnxsim/actions/workflows/model-regression.yml ) As far as I could say is that sometime onnxslim or onnxsim is better. The way onnxslim and onnxsim implement is different and now both is reliable so it seems reasonable to be selectable. How do you think? @inisis

@take-cheeze If onnxsim is now well-maintained, I would certainly pick onnxsim up, it's the only one.

Do you mean we should take onnxsim over onnxslim? When should users choose one over the other?

Keep onnxslim as the default simplifier and offer onnxsim as an
equivalent, user-selectable option for
modelopt.onnx.quantization.quantize(..., simplify=True) and the
--simplify CLI flag.

- quantize.py / __main__.py: add a simplify_backend argument
  (--simplify_backend) that selects between "onnxslim" (default,
  unchanged behavior) and "onnxsim". An unknown backend name or a
  missing onnxsim install fails loudly; genuine simplification failures
  still fall back gracefully to the original model.
- pyproject.toml / uv.lock: add onnxsim>=0.7.0 to the onnx extra
  alongside onnxslim. onnxsim 0.7.0 ships wheels for Python 3.12+
  and aarch64.
- test_quantize_api.py: update the _preprocess_onnx mock signature for
  the new argument.
- CHANGELOG.rst: document the new backend option under 0.47.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PYET7LC6SwmWpkCSN18T1Z
Signed-off-by: Claude <noreply@anthropic.com>
@take-cheeze
take-cheeze force-pushed the claude/re-enable-onnxsim-c1wpem branch from 8c7f03c to f07c462 Compare August 1, 2026 06:44

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Warning

CodeRabbit couldn't request changes on this pull request because it doesn't have sufficient GitHub permissions.

Please grant CodeRabbit Pull requests: Read and write permission and re-run the review.

👉 Steps to fix this

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@CHANGELOG.rst`:
- Line 63: Update the changelog entry for the simplify_backend option to qualify
the backend equivalence claim: state that both onnxslim and onnxsim aim to
preserve model semantics, while allowing their generated graphs to differ. Keep
the existing default backend and CLI/API option details unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 6dc045b0-eec4-495a-90c5-4fe93c8440cf

📥 Commits

Reviewing files that changed from the base of the PR and between 8c7f03c and f07c462.

⛔ Files ignored due to path filters (1)
  • uv.lock is excluded by !**/*.lock
📒 Files selected for processing (5)
  • CHANGELOG.rst
  • modelopt/onnx/quantization/__main__.py
  • modelopt/onnx/quantization/quantize.py
  • pyproject.toml
  • tests/unit/onnx/quantization/test_quantize_api.py
🚧 Files skipped from review as they are similar to previous changes (4)
  • pyproject.toml
  • tests/unit/onnx/quantization/test_quantize_api.py
  • modelopt/onnx/quantization/main.py
  • modelopt/onnx/quantization/quantize.py

Comment thread CHANGELOG.rst
- Add a ``constant_amax`` ``QuantizerAttributeConfig`` field that pins a quantizer's ``amax`` to a fixed value and skips activation calibration (no forward statistics collected). Unlike ``use_constant_amax`` (which hardcodes 448.0 for KV-cache cast math and registers no buffer), ``constant_amax`` stores the constant on the ``_amax`` buffer so it is used by both the fake-quant forward and the exported scaling factor. For NVFP4 activations the exported ``input_scale`` equals ``amax / (E2M1_MAX * E4M3_MAX)``, so ``constant_amax: 2688.0`` yields ``input_scale == 1.0``. Ships a new recipe ``modelopt_recipes/general/ptq/nvfp4_experts_only_input_scale1-kv_fp8_cast.yaml`` that applies this to the MoE expert activation quantizers.
- Add ``MaxCalibConfig.skip_forward_without_activation_calib`` (opt-in, default ``False``): when enabled, max calibration skips the ``forward_loop`` if no enabled quantizer needs data-driven activation statistics — e.g. an experts-only recipe whose activation quantizers all use ``constant_amax`` / ``use_constant_amax``, or dynamic / MX (MXFP4/MXFP8) quantization (and none has a static ``bias_calibrator``). Weight calibration still runs on the weight tensors directly, so the quantized weights are unchanged; only the wasted forward is avoided. It is opt-in because the ``forward_loop`` can carry caller-side effects (notably materializing sharded parameters under DeepSpeed ZeRO-3). The advanced algorithms that always need activations (MSE, local Hessian, SmoothQuant, SVDQuant, GPTQ) call ``max_calibrate`` directly and are unaffected. The ``nvfp4_experts_only_input_scale1-kv_fp8_cast`` recipe enables it.
- Add ``examples/minimax_m3/hf_ptq_mixed_mxfp8_nvfp4.py`` for streaming MiniMax-M3 export and a model-specific ``hf_ptq.py`` recipe that produces an MXFP8 language-model base with MSE-calibrated NVFP4 routed experts directly from BF16. The NVFP4 expert ``input_scale`` is fixed to 1.0.
- Add ``onnxsim`` as an alternative ONNX simplification backend for ``modelopt.onnx.quantization.quantize(..., simplify=True)`` (and the ``--simplify`` CLI flag). The new ``simplify_backend`` argument / ``--simplify_backend`` flag selects between ``"onnxslim"`` (default, unchanged) and ``"onnxsim"``; both produce an equivalent simplified model. ``onnxsim>=0.7.0`` now ships wheels for Python 3.12+ and aarch64.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -e
printf '%s\n' '--- relevant files ---'
git ls-files | rg '(^|/)(CHANGELOG\.rst|.*onnx.*|.*quantiz.*|.*simplif.*)' | head -200
printf '%s\n' '--- changelog context ---'
cat -n CHANGELOG.rst | sed -n '45,75p'
printf '%s\n' '--- backend references ---'
rg -n --hidden -g '!CHANGELOG.rst' 'simplify_backend|onnxslim|onnxsim|simplify=True|--simplify' . | head -250

Repository: NVIDIA/Model-Optimizer

Length of output: 30895


🏁 Script executed:

#!/bin/bash
set -e
printf '%s\n' '--- quantize implementation ---'
cat -n modelopt/onnx/quantization/quantize.py | sed -n '105,145p;205,260p;400,435p;570,600p;640,665p'
printf '%s\n' '--- CLI definition ---'
cat -n modelopt/onnx/quantization/__main__.py | sed -n '315,345p'
printf '%s\n' '--- simplification tests ---'
cat -n tests/gpu/onnx/test_simplify.py | sed -n '1,130p'
printf '%s\n' '--- API tests ---'
cat -n tests/unit/onnx/quantization/test_quantize_api.py | sed -n '1,125p'
printf '%s\n' '--- test and source inventory ---'
rg -n 'simplify_backend|onnxsim|onnxslim|equivalent simplified|semantics|checker' tests modelopt/onnx/quantization CHANGELOG.rst

Repository: NVIDIA/Model-Optimizer

Length of output: 33029


🏁 Script executed:

#!/bin/bash
set -e
python3 - <<'PY'
import ast
from pathlib import Path

source_path = Path("modelopt/onnx/quantization/quantize.py")
tree = ast.parse(source_path.read_text())
calls = []
for node in ast.walk(tree):
    if isinstance(node, ast.Call):
        fn = node.func
        if isinstance(fn, ast.Attribute) and isinstance(fn.value, ast.Name):
            if (fn.value.id, fn.attr) in {("onnxslim", "slim"), ("onnxsim", "simplify")}:
                calls.append((fn.value.id, fn.attr, ast.unparse(node)))
print("simplifier_calls:")
for item in calls:
    print(item)

test_text = Path("tests/gpu/onnx/test_simplify.py").read_text()
api_text = Path("tests/unit/onnx/quantization/test_quantize_api.py").read_text()
for name, text in [("tests/gpu/onnx/test_simplify.py", test_text),
                   ("tests/unit/onnx/quantization/test_quantize_api.py", api_text)]:
    print(f"{name}:")
    print("  mentions simplify_backend =", "simplify_backend" in text)
    print("  mentions onnxsim =", "onnxsim" in text)
    print("  calls quantize with simplify=True =", "simplify=True" in text)
PY
printf '%s\n' '--- dependency metadata context ---'
cat -n pyproject.toml | sed -n '60,80p'
printf '%s\n' '--- historical changelog context ---'
cat -n CHANGELOG.rst | sed -n '330,347p'

Repository: NVIDIA/Model-Optimizer

Length of output: 3085


Qualify the equivalence claim. onnxslim and onnxsim use different simplification calls, and no test compares their outputs. State that both aim to preserve model semantics, but the generated graph may differ by backend.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@CHANGELOG.rst` at line 63, Update the changelog entry for the
simplify_backend option to qualify the backend equivalence claim: state that
both onnxslim and onnxsim aim to preserve model semantics, while allowing their
generated graphs to differ. Keep the existing default backend and CLI/API option
details unchanged.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants